package com.junjie.food.orderServiceManager.service.impl;

import MountainMq.listener.AbstractMessageListener;
import MountainMq.sender.TransMessageSender;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.junjie.food.orderServiceManager.dao.OrderDetailDao;
import com.junjie.food.orderServiceManager.dto.OrderMessageDTO;
import com.junjie.food.orderServiceManager.enummeration.OrderStatus;
import com.junjie.food.orderServiceManager.pojo.OrderDetailPo;
import com.junjie.food.orderServiceManager.service.OrderMessageService;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

// 处理消息有关的逻辑
@Service
@Slf4j
// 指定工厂和消费者监听队列 配合@RabbitHandler使用
//@RabbitListener(containerFactory = "rabbitListenerContainerFactory",
//                queues = "queue.order")
// 这里继承了我们自定义的抽象类
public class OrderMessageServiceImpl extends AbstractMessageListener implements OrderMessageService {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OrderDetailDao orderDetailDao;
    @Autowired
    private TransMessageSender transMessageSender;

    @RabbitListener(queues = "test")
    public void test(String message){
        System.out.println(message);
    }

    /**
     * 实现的MountainMessage中的定义监听器监听的方法
     * 主要写执行业务的代码
     * @param message
     */
    @Override
    public void receiveMessage(Message message) {
        // 将字节数组转换成字符串
        String messageBody = new String(message.getBody());
        log.info("messageBody:{}",messageBody);
        try{
            // 将消息体反序列化成DTO
            OrderMessageDTO orderMessageDTO = objectMapper.readValue(messageBody,OrderMessageDTO.class);
            // 数据库中读取订单PO
            OrderDetailPo orderDetailPo = orderDetailDao.selectOrder(orderMessageDTO.getOrderId());
            // 我们怎么知道当前消息是谁发过来的？从数据库看订单状态，再判断即可
            switch (orderDetailPo.getStatus()){
                case ORDER_CREATING: // 订单创建中状态，餐厅微服务发来的
                    // 商家是否确认订单  商家是否填写了price
                    if(orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()){
                        orderDetailPo.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
                        orderDetailPo.setPrice(orderMessageDTO.getPrice());
                        // 订单修改状态和价格
                        orderDetailDao.update(orderDetailPo);
                        // 使用我们封装的sender去发送消息
                        transMessageSender.send("exchange.order.deliveryman", "key.deliveryman",
                                orderMessageDTO);

                    }else{ // 订单失败
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break; case RESTAURANT_CONFIRMED:// 餐厅已确认状态，期间餐厅微服务发消息给骑手微服务，找了个骑手接单，然后发消息给订单微服务
                    // 如果没有骑手ID，就说明骑手微服务异常，或者没找到骑手
                    if (null != orderMessageDTO.getDeliverymanId()) {
                        // 订单状态为骑手已确认
                        orderDetailPo.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
                        orderDetailPo.setDeliverymanId(orderMessageDTO.getDeliverymanId());
                        // 修改订单状态
                        orderDetailDao.update(orderDetailPo);
                        transMessageSender.send("exchange.order.settlement", "key.settlement",orderMessageDTO);

                    } else { // 没有骑手ID就订单失败咯
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break; case DELIVERYMAN_CONFIRMED: // 结算微服务处理好后，将消息返回给订单微服务
                    // 结算完了，准备发信息给积分微服务
                    if (null != orderMessageDTO.getSettlementId()) {
                        orderDetailPo.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
                        orderDetailPo.setSettlementId(orderMessageDTO.getSettlementId());
                        orderDetailDao.update(orderDetailPo);
                        transMessageSender.send("exchange.order.reward", "key.reward",orderMessageDTO);

                    } else { // 如果没有结算ID，就说明结算失败，更新订单状态，并不再发消息
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break; case SETTLEMENT_CONFIRMED: // 积分微服务处理好了，消息发给订单微服务
                    if (null != orderMessageDTO.getRewardId()) {
                        orderDetailPo.setStatus(OrderStatus.ORDER_CREATED);
                        orderDetailPo.setRewardId(orderMessageDTO.getRewardId());
                        orderDetailDao.update(orderDetailPo);
                    } else {
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break;
            }
        } catch (Exception e){
            // 不建议使用e.printStack() 不受日志框架控制
            log.error(e.getMessage(),e);
        }
    }



    // 使用RabbitListener
    @Override
//    @RabbitHandler(isDefault = true) // 所有消息不管类型是什么，直接调用该方法
    @RabbitListener(containerFactory = "rabbitListenerContainerFactory",
            queues = "queue.order")
    // 当然这个注解还可以和别的注解结合起来 开机自动创建队列之类的
    // 所以这里属性必须传入rabbitAdmin的bean名
//    @RabbitListener(containerFactory = "rabbitListenerContainerFactory",
//            queues = "queue.order",
//            admin = "rabbitAdmin",
//            bindings = {
//                @QueueBinding(
//                        value=@Queue(
//                                name = "queue.order",
//                                arguments = {
//                                        @Argument(
//                                                name="x-message-ttl",
//                                                value = "1000",
//                                                type = "java.lang.Integer"
//                                        ),
//                                        @Argument(
//                                                name="x-dead-letter-exchange",
//                                                value = "exchange.dlx"
//                                        )
//                                }
//                        ),
//                        exchange = @Exchange(name = "exchange.order.restaurant",type = ExchangeTypes.DIRECT),
//                        key = "key.order"
//                )
//            })
    public void handleMessage(@Payload Message message) throws IOException, TimeoutException, InterruptedException {
        String messageBody = new String(message.getBody());
        log.info("messageBody:{}",messageBody);
        // 将字节数组转换成字符串
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("110.40.176.175");
        try{
            // 将消息体反序列化成DTO
            OrderMessageDTO orderMessageDTO = objectMapper.readValue(messageBody,OrderMessageDTO.class);
            // 数据库中读取订单PO
            OrderDetailPo orderDetailPo = orderDetailDao.selectOrder(orderMessageDTO.getOrderId());
            // 我们怎么知道当前消息是谁发过来的？从数据库看订单状态，再判断即可
            switch (orderDetailPo.getStatus()){
                case ORDER_CREATING: // 订单创建中状态，餐厅微服务发来的
                    // 商家是否确认订单  商家是否填写了price
                    if(orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()){
                        orderDetailPo.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
                        orderDetailPo.setPrice(orderMessageDTO.getPrice());
                        // 订单修改状态和价格
                        orderDetailDao.update(orderDetailPo);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            // 发请求给骑手微服务
                            channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
                                    messageToSend.getBytes());
                        }
                    }else{ // 订单失败
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break; case RESTAURANT_CONFIRMED:// 餐厅已确认状态，期间餐厅微服务发消息给骑手微服务，找了个骑手接单，然后发消息给订单微服务
                    // 如果没有骑手ID，就说明骑手微服务异常，或者没找到骑手
                    if (null != orderMessageDTO.getDeliverymanId()) {
                        // 订单状态为骑手已确认
                        orderDetailPo.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
                        orderDetailPo.setDeliverymanId(orderMessageDTO.getDeliverymanId());
                        // 修改订单状态
                        orderDetailDao.update(orderDetailPo);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            // 发消息给结算微服务
                            channel.basicPublish("exchange.order.settlement", "key.settlement", null,
                                    messageToSend.getBytes());
                        }
                    } else { // 没有骑手ID就订单失败咯
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break; case DELIVERYMAN_CONFIRMED: // 结算微服务处理好后，将消息返回给订单微服务
                    // 结算完了，准备发信息给积分微服务
                    if (null != orderMessageDTO.getSettlementId()) {
                        orderDetailPo.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
                        orderDetailPo.setSettlementId(orderMessageDTO.getSettlementId());
                        orderDetailDao.update(orderDetailPo);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            // 发消息给积分微服务
                            channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());
                        }
                    } else { // 如果没有结算ID，就说明结算失败，更新订单状态，并不再发消息
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break; case SETTLEMENT_CONFIRMED: // 积分微服务处理好了，消息发给订单微服务
                    if (null != orderMessageDTO.getRewardId()) {
                        orderDetailPo.setStatus(OrderStatus.ORDER_CREATED);
                        orderDetailPo.setRewardId(orderMessageDTO.getRewardId());
                        orderDetailDao.update(orderDetailPo);
                    } else {
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break;
            }
        } catch (Exception e){
            // 不建议使用e.printStack()
            log.error(e.getMessage(),e);
        }
    }

    @Override
    public void handleMessage(byte[] message){
        {
            // 将字节数组转换成字符串
            String messageBody = new String(message);
            ConnectionFactory connectionFactory = new ConnectionFactory();
            connectionFactory.setHost("110.40.176.175");
            try{
                // 将消息体反序列化成DTO
                OrderMessageDTO orderMessageDTO = objectMapper.readValue(messageBody,OrderMessageDTO.class);
                // 数据库中读取订单PO
                OrderDetailPo orderDetailPo = orderDetailDao.selectOrder(orderMessageDTO.getOrderId());

                // 我们怎么知道当前消息是谁发过来的？从数据库看订单状态，再判断即可
                switch (orderDetailPo.getStatus()){
                    case ORDER_CREATING: // 订单创建中状态，餐厅微服务发来的
                        // 商家是否确认订单  商家是否填写了price
                        if(orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()){
                            orderDetailPo.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
                            orderDetailPo.setPrice(orderMessageDTO.getPrice());
                            // 订单修改状态和价格
                            orderDetailDao.update(orderDetailPo);
                            try (Connection connection = connectionFactory.newConnection();
                                 Channel channel = connection.createChannel()) {
                                String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                                // 发请求给骑手微服务
                                channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
                                        messageToSend.getBytes());
                            }
                        }else{ // 订单失败
                            orderDetailPo.setStatus(OrderStatus.FAILED);
                            orderDetailDao.update(orderDetailPo);
                        }
                        break;
                    case RESTAURANT_CONFIRMED:
                        // 餐厅已确认状态，期间餐厅微服务发消息给骑手微服务，找了个骑手接单，然后发消息给订单微服务
                        // 如果没有骑手ID，就说明骑手微服务异常，或者没找到骑手
                        if (null != orderMessageDTO.getDeliverymanId()) {
                            // 订单状态为骑手已确认
                            orderDetailPo.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
                            orderDetailPo.setDeliverymanId(orderMessageDTO.getDeliverymanId());
                            // 修改订单状态
                            orderDetailDao.update(orderDetailPo);
                            try (Connection connection = connectionFactory.newConnection();
                                 Channel channel = connection.createChannel()) {
                                String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                                // 发消息给结算微服务
                                channel.basicPublish("exchange.order.settlement", "key.settlement", null,
                                        messageToSend.getBytes());
                            }
                        } else { // 没有骑手ID就订单失败咯
                            orderDetailPo.setStatus(OrderStatus.FAILED);
                            orderDetailDao.update(orderDetailPo);
                        }
                        break;
                    case DELIVERYMAN_CONFIRMED: // 结算微服务处理好后，将消息返回给订单微服务
                        // 结算完了，准备发信息给积分微服务
                        if (null != orderMessageDTO.getSettlementId()) {
                            orderDetailPo.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
                            orderDetailPo.setSettlementId(orderMessageDTO.getSettlementId());
                            orderDetailDao.update(orderDetailPo);
                            try (Connection connection = connectionFactory.newConnection();
                                 Channel channel = connection.createChannel()) {
                                String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                                // 发消息给积分微服务
                                channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());
                            }
                        } else { // 如果没有结算ID，就说明结算失败，更新订单状态，并不再发消息
                            orderDetailPo.setStatus(OrderStatus.FAILED);
                            orderDetailDao.update(orderDetailPo);
                        }
                        break;
                    case SETTLEMENT_CONFIRMED: // 积分微服务处理好了，消息发给订单微服务
                        if (null != orderMessageDTO.getRewardId()) {
                            orderDetailPo.setStatus(OrderStatus.ORDER_CREATED);
                            orderDetailPo.setRewardId(orderMessageDTO.getRewardId());
                            orderDetailDao.update(orderDetailPo);
                        } else {
                            orderDetailPo.setStatus(OrderStatus.FAILED);
                            orderDetailDao.update(orderDetailPo);
                        }
                        break;
                }
            } catch (Exception e){
                // 不建议使用e.printStack()
                log.error(e.getMessage(),e);
            }

        }
    }


    // 测试自定义转换器，原本是byte[]数组，现在直接自定义转换器将消息转换成OrderMessageDTO
    @Override
    public void handleMessage(OrderMessageDTO message) throws IOException, TimeoutException, InterruptedException {
        // 这里只是换了形参，实际逻辑可以直接参考上面的方法，这里为了简单就直接打印了
        System.out.println(message);
    }


    // 函数式接口不需要单独声明一个类去实现方法

    DeliverCallback deliverCallback = ((consumerTag,message)->{
        // 将字节数组转换成字符串
        String messageBody = new String(message.getBody());
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("110.40.176.175");
        try{
            // 将消息体反序列化成DTO
            OrderMessageDTO orderMessageDTO = objectMapper.readValue(messageBody,OrderMessageDTO.class);
            // 数据库中读取订单PO
            OrderDetailPo orderDetailPo = orderDetailDao.selectOrder(orderMessageDTO.getOrderId());

            // 我们怎么知道当前消息是谁发过来的？从数据库看订单状态，再判断即可
            switch (orderDetailPo.getStatus()){
                case ORDER_CREATING: // 订单创建中状态，餐厅微服务发来的
                    // 商家是否确认订单  商家是否填写了price
                    if(orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()){
                        orderDetailPo.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
                        orderDetailPo.setPrice(orderMessageDTO.getPrice());
                        // 订单修改状态和价格
                        orderDetailDao.update(orderDetailPo);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            // 发请求给骑手微服务
                            channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
                                    messageToSend.getBytes());
                        }
                    }else{ // 订单失败
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break;
                case RESTAURANT_CONFIRMED:
                    // 餐厅已确认状态，期间餐厅微服务发消息给骑手微服务，找了个骑手接单，然后发消息给订单微服务
                    // 如果没有骑手ID，就说明骑手微服务异常，或者没找到骑手
                    if (null != orderMessageDTO.getDeliverymanId()) {
                        // 订单状态为骑手已确认
                        orderDetailPo.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
                        orderDetailPo.setDeliverymanId(orderMessageDTO.getDeliverymanId());
                        // 修改订单状态
                        orderDetailDao.update(orderDetailPo);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            // 发消息给结算微服务
                            channel.basicPublish("exchange.order.settlement", "key.settlement", null,
                                    messageToSend.getBytes());
                        }
                    } else { // 没有骑手ID就订单失败咯
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break;
                case DELIVERYMAN_CONFIRMED: // 结算微服务处理好后，将消息返回给订单微服务
                    // 结算完了，准备发信息给积分微服务
                    if (null != orderMessageDTO.getSettlementId()) {
                        orderDetailPo.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
                        orderDetailPo.setSettlementId(orderMessageDTO.getSettlementId());
                        orderDetailDao.update(orderDetailPo);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            // 发消息给积分微服务
                            channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());
                        }
                    } else { // 如果没有结算ID，就说明结算失败，更新订单状态，并不再发消息
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break;
                case SETTLEMENT_CONFIRMED: // 积分微服务处理好了，消息发给订单微服务
                    if (null != orderMessageDTO.getRewardId()) {
                        orderDetailPo.setStatus(OrderStatus.ORDER_CREATED);
                        orderDetailPo.setRewardId(orderMessageDTO.getRewardId());
                        orderDetailDao.update(orderDetailPo);
                    } else {
                        orderDetailPo.setStatus(OrderStatus.FAILED);
                        orderDetailDao.update(orderDetailPo);
                    }
                    break;
            }
        } catch (Exception e){
            // 不建议使用e.printStack()
            log.error(e.getMessage(),e);
        }

    });
}
